# -*- coding: utf-8 -*-
# @Date：2024/9/30 14:22:13
# @Author：CJiaの青姝
# @FileName：login
# @Editor：PyCharm2024
# @Remark：
from typing import Any
from typing_extensions import Self

from django.forms import model_to_dict
from django.core.cache import cache
from backend.settings import TOKEN_LIFETIME
from auths.models import User
from ninja import Router, Field, Schema, ModelSchema

from utils.cj_bcrypt import encrypt_pass, decrypt_pass
from utils.cj_jwt import generate_token
from utils.userinfo import get_user_info_from_token, get_user_logout_token
from utils.cj_response import SuccessResponse, ErrorResponse

router = Router()


class LoginSchemaIn(ModelSchema):

    def model_validate(
            cls,
            obj: Any,
            *,
            strict: bool | None = None,
            from_attributes: bool | None = None,
            context: Any | None = None,
    ) -> Self:
        if obj.email.strip() is None or obj.password.strip() is None:
            return "用户名或密码不能为空", 400
        else:
            # 查找邮箱是否存在
            user = User.objects.filter(email=obj.email).first()
            if user:
                # 缓存获取加密盐
                if cache.get(obj.email + "_salt"):
                    # 密码加密
                    obj.password = encrypt_pass(obj.password, user.salt.encode())
                else:
                    # 缓存则在数据库查找保存到缓存里
                    cache.set(user.email + "_salt", user.salt, TOKEN_LIFETIME)
                    # 密码加密
                    obj.password = encrypt_pass(obj.password, user.salt.encode())
                # 返回请求数据
                return obj.dict(), 200
            else:
                # 找不到提示错误
                return "用户邮箱不存在，请先注册", 400

    class Config:
        title = '用户登录参数'
        model = User
        model_fields = ["email", "password"]


class LoginSchemaOut(Schema):
    token: str = Field(None, description="token", alias="token")
    bearerToken: str = Field(None, description="完整token", alias="bearerToken")

    class Config:
        title = "用户登录对象"


class UserSchemaOut(ModelSchema):
    class Config:
        title = '用户对象实例'
        model = User
        model_exclude = ["password", "password_decrypt", "salt"]


@router.post("/login", auth=None, response=LoginSchemaOut, summary="用户登录")
def login(request: Any, data: LoginSchemaIn) -> SuccessResponse | ErrorResponse:
    """ 用户登录 """
    message, code = data.model_validate(data)
    if code == 200:
        # 校验密码
        user = User.objects.filter(email=message['email']).first()
        if user:
            encrypt = decrypt_pass(user.password_decrypt, message['password'])
            if encrypt:
                # 记录登录用户信息
                request.user = user
                # json化
                user_obj_dic = model_to_dict(user)
                # 生成token
                jwt = generate_token(user_obj_dic)
                # 构建数据
                result = {
                    "token": jwt,
                    "bearerToken": f"Bearer {jwt}",
                }
                # 返回结果
                return SuccessResponse(data=result, msg="登录成功")
            else:
                return ErrorResponse(msg="用户密码错误，请重新输入")
        else:
            return ErrorResponse(msg="用户邮箱不存在，请先注册")
    else:
        return ErrorResponse(msg=message)


@router.post("/logout", summary="用户退出登录")
def logout(request) -> SuccessResponse | ErrorResponse:
    """ 用户退出登录 """
    # 调用用户注销方法
    result = get_user_logout_token(request)
    # 返回结果
    return SuccessResponse(data=result)


@router.post("/userinfo", response=UserSchemaOut, summary="获取用户信息")
def userinfo(request) -> SuccessResponse | ErrorResponse:
    """ 获取用户信息 """
    result = get_user_info_from_token(request)
    # 返回结果
    return result
